<template>
  <view class="date-picker">
    <m-picker
      ref="picker"
      v-model="innerValue"
      :title="getTitle"
      :visible="visible"
      :options="options"
      :poppable="poppable"
      :placeholder="placeholder"
      @change="handleChange"
      @confirm="handleConfirm"
      @close="handleClose"
      @open="handleOpen"
    />
  </view>
</template>

<script lang="ts">
import dayjs from 'dayjs'
import getCurrentComponent from '@/utils/get-current-component'
import { defineComponent, reactive, toRefs, computed, inject } from '@vue/composition-api'
import {
  getCurrentDate,
  getMinDate,
  getMaxDate,
  getYears,
  getMonths,
  getDates,
  getHours,
  getMinutes,
  getSeconds,
  setMonth,
  setDate,
  setHour,
  setMinute,
  setSecond,
  getDefaultValue,
} from './utils'

export default defineComponent({
  props: {
    value: {
      type: [Date, String, Number],
      default: null,
    },
    visible: {
      type: Boolean,
      default: false,
    },
    type: {
      type: String,
      default: 'date', // date datetime time year-month
    },
    minDate: {
      type: [Date, String, Number],
      default: null,
    },
    maxDate: {
      type: [Date, String, Number],
      default: null,
    },
    title: {
      type: String,
      default: null,
    },
    poppable: {
      type: Boolean,
      default: false,
    },
    placeholder: {
      type: String,
      default: '',
    },
    valueFormat: {
      type: String,
      default: null,
    },
    labelFormat: {
      type: String,
      default: null,
    },
  },
  emits: ['confirm', 'close', 'open'],
  setup(props, { emit }) {
    const formItem: any = inject('formItem', null)
    const vm: any = getCurrentComponent()
    let minDate
    let maxDate

    const state = reactive({
      innerValue: [] as number[],
      year: 0,
      month: 0,
      date: 0,
      hour: 0,
      minute: 0,
      second: 0,
      options: [],
    })

    const handleChange = ({ newVal, columnIndex, values }) => {
      if (props.type === 'time') {
        if (columnIndex === 0) {
          state.hour = newVal
          const dateInfo = {
            minDate,
            maxDate,
            year: state.year,
            month: state.month,
            date: state.date,
            hour: values[0],
          }
          const newMinute = setMinute(dateInfo, state, vm, 1)

          values[values.length - 1] = newMinute

          handleChange({
            newVal: newMinute,
            columnIndex: columnIndex + 1,
            values,
          })
          return
        }

        if (columnIndex === 1) {
          state.minute = newVal

          const dateInfo = {
            minDate,
            maxDate,
            year: state.year,
            month: state.month,
            date: state.date,
            hour: values[0],
            minute: values[1],
          }
          const newSecond = setSecond(dateInfo, state, vm, 2)

          values[values.length - 1] = newSecond

          handleChange({
            newVal: newSecond,
            columnIndex: columnIndex + 1,
            values,
          })

          return
        }

        if (columnIndex === 2) {
          state.second = newVal
          return
        }

        return
      }

      if (columnIndex === 0) {
        // 重新计算月
        state.year = newVal
        const dateInfo = {
          minDate,
          maxDate,
          year: values[0],
        }
        const newMonth = setMonth(dateInfo, state, vm)

        values[values.length - 1] = newMonth

        handleChange({
          newVal: newMonth,
          columnIndex: columnIndex + 1,
          values,
        })

        return
      }

      if (columnIndex === 1) {
        // 重新计算日
        state.month = newVal

        if (props.type === 'yearmonth') {
          return
        }
        const dateInfo = {
          minDate,
          maxDate,
          year: values[0],
          month: values[1],
        }
        const newDate = setDate(dateInfo, state, vm)

        values[values.length - 1] = newDate

        handleChange({
          newVal: newDate,
          columnIndex: columnIndex + 1,
          values,
        })

        return
      }

      if (columnIndex === 2) {
        state.date = newVal

        if (props.type === 'date') {
          return
        }

        const dateInfo = {
          minDate,
          maxDate,
          year: values[0],
          month: values[1],
          date: values[2],
        }

        const newHour = setHour(dateInfo, state, vm)

        values[values.length - 1] = newHour

        handleChange({
          newVal: newHour,
          columnIndex: columnIndex + 1,
          values,
        })

        return
      }

      if (columnIndex === 3) {
        state.hour = newVal

        if (props.type === 'date') {
          return
        }

        const dateInfo = {
          minDate,
          maxDate,
          year: values[0],
          month: values[1],
          date: values[2],
          hour: values[3],
        }

        setMinute(dateInfo, state, vm)

        return
      }

      if (columnIndex === 4) {
        state.minute = newVal
      }
    }

    const getTitle = computed(() => {
      if (props.title) {
        return props.title
      }

      if (props.type === 'yearmonth') {
        return '选择年月'
      }

      if (props.type === 'datetime') {
        return '选择日期时间'
      }

      if (props.type === 'time') {
        return '请选择时间'
      }

      return '请选择日期'
    })

    const getLabelFormat = computed(() => {
      if (props.labelFormat) {
        return props.labelFormat
      }

      if (props.type === 'yearmonth') {
        return 'YYYY年MM月'
      }

      if (props.type === 'datetime') {
        return 'YYYY年MM月DD日 HH时mm分'
      }

      if (props.type === 'time') {
        return 'HH时mm分ss秒'
      }

      return 'YYYY年MM月DD日'
    })

    const getValueFormat = computed(() => {
      if (props.valueFormat) {
        return props.valueFormat
      }

      if (props.type === 'yearmonth') {
        return 'YYYY-MM'
      }

      if (props.type === 'datetime') {
        return 'YYYY-MM-DD HH:mm'
      }

      if (props.type === 'time') {
        return 'HH:mm:ss'
      }

      return 'YYYY-MM-DD'
    })

    const handleConfirm = (label, val) => {
      let date

      if (formItem && formItem.validate) {
        formItem && formItem.validate()
      }

      if (props.type === 'date') {
        date = dayjs(new Date(val[0], val[1], val[2]))
      } else if (props.type === 'time') {
        date = dayjs(new Date(2000, 0, 1, val[0], val[1], val[2]))
      } else if (props.type === 'datetime') {
        date = dayjs(new Date(val[0], val[1], val[2], val[3], val[4]))
      } else if (props.type === 'yearmonth') {
        date = dayjs(new Date(val[0], val[1], 1))
      }

      let rtvLabel = date.format(getLabelFormat.value)
      let rtvValue = date.format(getValueFormat.value)

      emit('input', rtvValue)
      emit('confirm', rtvLabel, rtvValue)
      handleClose()
    }

    const handleClose = () => {
      emit('update:visible', false)
      emit('close')
    }

    const handleOpen = () => {
      let currentDate = getCurrentDate(props)
      let nowYear = currentDate.year()
      minDate = getMinDate(props, nowYear)
      maxDate = getMaxDate(props, nowYear)
      let defaultYear
      let defaultMonth
      let defaultDate
      let defaultHour
      let defaultMinute
      let defaultSecond

      if (currentDate.valueOf() < minDate.valueOf()) {
        defaultYear = minDate.year()
        defaultMonth = minDate.month()
        defaultDate = minDate.date()
        defaultHour = minDate.hour()
        defaultMinute = minDate.minute()
        defaultSecond = minDate.second()
      } else if (currentDate.valueOf() > maxDate.valueOf()) {
        defaultYear = maxDate.year()
        defaultMonth = maxDate.month()
        defaultDate = maxDate.date()
        defaultHour = maxDate.hour()
        defaultMinute = maxDate.minute()
        defaultSecond = maxDate.second()
      } else {
        defaultYear = currentDate.year()
        defaultMonth = currentDate.month()
        defaultDate = currentDate.date()
        defaultHour = currentDate.hour()
        defaultMinute = currentDate.minute()
        defaultSecond = currentDate.second()
      }

      const dateInfo = {
        minDate,
        maxDate,
        year: defaultYear,
        month: defaultMonth,
        date: defaultDate,
        hour: defaultHour,
        minute: defaultMinute,
      }

      const years = getYears(dateInfo)
      const months = getMonths(dateInfo)
      const dates = getDates(dateInfo)
      const hours = getHours(dateInfo)
      const minutes = getMinutes(dateInfo)
      const seconds = getSeconds(dateInfo)
      const innerValue = [defaultYear, defaultMonth, defaultDate, defaultHour, defaultMinute, defaultSecond]
      const options = [
        { values: years },
        { values: months },
        { values: dates },
        { values: hours },
        { values: minutes },
        { values: seconds },
      ]

      state.innerValue = getDefaultValue(props, innerValue)
      state.year = defaultYear
      state.month = defaultMonth
      state.date = defaultDate
      state.hour = defaultHour
      state.minute = defaultMinute
      state.second = defaultSecond
      state.options = getDefaultValue(props, options)

      if (props.type === 'time') {
        // 分
        const newMinute = setMinute(dateInfo, state, vm, 1)
        state.minute = newMinute

        // 秒
        const newSecond = setSecond(dateInfo, state, vm, 2)
        state.second = newSecond

        state.innerValue = [defaultHour, newMinute, newSecond]

        return
      }
      // 重新计算月
      const newMonth = setMonth(dateInfo, state, vm)
      // 日
      const newDate = setDate(dateInfo, state, vm)

      state.month = newMonth
      state.date = newDate

      if (props.type === 'datetime') {
        // 时
        const newHour = setHour(dateInfo, state, vm)
        // 分
        const newMinute = setMinute(dateInfo, state, vm)
        state.hour = newHour
        state.minute = newMinute
        state.innerValue = [defaultYear, newMonth, newDate, newHour, newMinute]
      } else {
        state.innerValue = [defaultYear, newMonth, newDate]
      }
    }

    return {
      ...toRefs(state),
      handleChange,
      handleConfirm,
      handleClose,
      handleOpen,
      getTitle,
    }
  },
})
</script>
<style lang="scss" scoped>
.date-picker {
}
</style>
